Skip to content

Conversation

@zhaoxiaofeng876
Copy link
Contributor

@zhaoxiaofeng876 zhaoxiaofeng876 commented Jan 9, 2026

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • Documentation

    • Added multiple tag-input demos covering clearable, collapsed, disabled/readonly, draggable, max limit, prefix/suffix, and separator behaviors; updated basic usage example to show a disabled variant.
  • Style

    • Refined disabled-state styling for the tag-input so the inner input reflects the disabled appearance consistently.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

Walkthrough

Multiple new TinyTagInput demo components were added (both Options and Composition API) demonstrating clearable, collapsed, disabled/readonly, draggable, max, prefix/suffix, and separator usages; two basic-usage demos had a second input made disabled; demo metadata was updated and disabled-state styling in the theme was refactored.

Changes

Cohort / File(s) Summary
Modified basic usage demos
examples/sites/demos/pc/app/tag-input/basic-usage.vue, examples/sites/demos/pc/app/tag-input/basic-usage-composition-api.vue
Second TinyTagInput input was changed to include the disabled attribute (rendered as a multiline prop block in the composition-api file).
New clearable-tag demos
examples/sites/demos/pc/app/tag-input/clearable-tag.vue, examples/sites/demos/pc/app/tag-input/clearable-tag-composition-api.vue
Added demos showing clearable prop with v-model bound tag arrays and placeholder; includes scoped spacing styles.
New collapsed-tag demos
examples/sites/demos/pc/app/tag-input/collapsed-tag.vue, examples/sites/demos/pc/app/tag-input/collapsed-tag-composition-api.vue
Added demos demonstrating min-collapsed-num behavior with initial tag arrays and placeholder.
New disabled/readonly demos
examples/sites/demos/pc/app/tag-input/disabled-readonly.vue, examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue
Added demos showing both disabled and readonly TinyTagInput instances bound to separate tag arrays.
New draggable-tag demos
examples/sites/demos/pc/app/tag-input/draggable-tag.vue, examples/sites/demos/pc/app/tag-input/draggable-tag-composition-api.vue
Added demos enabling draggable for tag reordering with v-model arrays.
New max-tag demos
examples/sites/demos/pc/app/tag-input/max.vue, examples/sites/demos/pc/app/tag-input/max-composition-api.vue
Added demos showcasing max prop limiting tag count with initial arrays exceeding the limit.
New prefix/suffix demos
examples/sites/demos/pc/app/tag-input/prefix-suffix.vue, examples/sites/demos/pc/app/tag-input/prefix-suffix-composition-api.vue
Added demos illustrating custom prefix and suffix slots wrapping the tag input.
New separator-tag demos
examples/sites/demos/pc/app/tag-input/separator-tag.vue, examples/sites/demos/pc/app/tag-input/separator-tag-composition-api.vue
Added demos demonstrating separator prop (comma example) for parsing input into tags.
Demo registry & theme updates
examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js, packages/theme/src/tag-input/index.less
Added seven new demo entries to the demo registry; refactored disabled-state styling to apply a dedicated :disabled rule to the inner element and removed the previous combined selector.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hopped through demos, tags in a line,
Clearable, dragged, and collapsed so fine.
Disabled and styled, new examples to show,
Little inputs ready to grow.
✨ Hop on—more tiny tags to know!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'docs(tag-input): add example' accurately describes the main change—adding multiple example components and documentation entries for the tag-input component.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Fix all issues with AI agents
In @examples/sites/demos/pc/app/tag-input/clearable-tag-composition-api.vue:
- Around line 7-14: The v-model bound variable "data" is declared with
reactive([...]) preventing reassignment when TinyTagInput emits a new array;
change its declaration to use ref([...]) instead (i.e., replace const data =
reactive([...]) with const data = ref([...])) so v-model can assign the new
array correctly, and keep using "data" in the template (Vue will handle .value
for reactivity).

In @examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue:
- Around line 1-6: The labels in the template are inconsistent and cramped:
change the full-width Chinese colon after "readonly:" to an ASCII colon
"readonly:" so both labels match, and wrap each tiny-tag-input with its label in
its own block element (e.g., a div or p) to improve layout and spacing for the
two controls (update the span + tiny-tag-input pairs that reference
v-model="data" and v-model="data1").
- Around line 1-14: The template uses placeholder (undefined) and binds v-model
to reactive arrays which should be Refs; define a placeholder constant and
change data and data1 to use ref([...]) instead of reactive([...]) so
TinyTagInput's v-model receives a Ref; update imports to include ref and ensure
placeholder is declared in the script setup.

In @examples/sites/demos/pc/app/tag-input/disabled-readonly.vue:
- Around line 3-4: Change the punctuation in the label for the readonly example
to match the disabled example: replace the Chinese full-width colon after the
"readonly" span with an English ASCII colon and space so both labels use ": "
(affecting the span before the tiny-tag-input bound to v-model="data1"); ensure
the visible text reads "readonly: " to match the "disabled: " label.

In @examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js:
- Line 86: The English demo name 'en-US' currently reads "basic usage" but
should match the Chinese label "自定义前后缀"; update the 'en-US' value in the demo
metadata (the entry keyed by 'en-US' in tag-input.js) to an appropriate
descriptive English string such as "Custom Prefix and Suffix" so the English and
Chinese demo names are consistent.
- Line 38: The English demo title is wrong: update the 'en-US' entry in the demo
metadata (the object with 'en-US': 'basic usage') so it matches the Chinese
'最大标签数' — e.g., change the value to a descriptive English label like "Maximum
tags" or "Maximum number of tags" for the demo in tag-input.js.
- Line 62: The en-US title value for the demo is incorrect—update the 'en-US'
entry that currently reads 'basic usage' to an English phrase matching the
Chinese description '可清空标签' (e.g., 'clearable tags' or 'clearable tag input') so
the demo name aligns across locales; locate the object containing the 'en-US'
key in tag-input.js and replace its value accordingly.
- Line 50: Update the English demo name in tag-input.js so the 'en-US' entry
matches the Chinese description '折叠标签' — replace the current 'basic usage'
string with an appropriate translation such as 'Collapsible Tags' (i.e., change
the value for the 'en-US' key).
- Line 74: Replace the current 'en-US' demo name value ('basic usage') with an
English phrase matching the Chinese description '分隔符输入标签' by updating the
locale/name mapping where the 'en-US' key is defined in tag-input.js — e.g.,
change it to "Separator Tag Input" or "Delimiter Tag Input" so the English demo
name accurately reflects the Chinese description.
- Line 26: The English demo title is wrong: update the 'en-US' value currently
set to 'basic usage' to match the Chinese name '禁用与只读' (e.g., use "Disabled and
Read-only" or "Disabled & Readonly") so the demo's 'en-US' entry accurately
describes the demo; locate the 'en-US' key in tag-input.js and replace its
string value accordingly.
- Line 98: The demo's English name currently reads 'basic usage'—update the
locale entry for 'en-US' in tag-input.js (the object containing the demo name
alongside the Chinese '可拖拽标签') to a matching English description such as
'Draggable tags' (or 'Draggable Tag Input') so the English demo name reflects
the Chinese description.

In @packages/theme/src/tag-input/index.less:
- Around line 50-52: Remove the unnecessary !important from the disabled rule:
in the .@{tag-input-prefix-cls}-inner:disabled selector drop the "!important" on
background-color and rely on the :disabled specificity to apply
var(--tv-TagInput-bg-color-disabled); if you find this overridden elsewhere,
increase selector specificity (e.g., add the element or state) rather than
reintroducing !important.
🧹 Nitpick comments (9)
examples/sites/demos/pc/app/tag-input/draggable-tag-composition-api.vue (1)

11-11: Consider using ref() instead of reactive() for arrays with v-model.

When binding arrays with v-model, if the component replaces the array reference entirely (rather than mutating it), reactive() can lose reactivity. Vue 3 best practice recommends ref() for primitive arrays bound to v-model.

♻️ Proposed refactor
-const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])

Note: If using ref(), the template binding remains the same since Vue automatically unwraps refs in templates.

examples/sites/demos/pc/app/tag-input/basic-usage-composition-api.vue (1)

19-21: Consider using ref() instead of reactive() for arrays with v-model.

Similar to best practices in Vue 3, when binding arrays with v-model, ref() is preferred over reactive() to avoid potential reactivity loss if the component replaces the array reference.

♻️ Proposed refactor
-const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
-const data1 = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
-const data2 = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data1 = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data2 = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])

Note: Template bindings remain unchanged as Vue automatically unwraps refs in templates.

examples/sites/demos/pc/app/tag-input/collapsed-tag-composition-api.vue (1)

11-11: Consider using ref() instead of reactive() for the array.

In Vue 3 Composition API, ref() is generally preferred for arrays as it provides better type inference and is more idiomatic. Using reactive() on a plain array works but is less conventional.

♻️ Suggested refactor
-const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])

Note: This pattern appears in other composition API demos in this PR. Consider applying this refactor consistently across all examples.

examples/sites/demos/pc/app/tag-input/max-composition-api.vue (2)

11-11: Consider using ref() instead of reactive() for the array.

In Vue 3 Composition API, ref() is generally preferred for arrays as it provides better type inference and is more idiomatic.

♻️ Suggested refactor
-const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])

12-13: Consider using ref() for consistency with other demos.

While using const for static primitive values is valid, other composition API demos in this PR use ref() for similar values (e.g., placeholder in collapsed-tag-composition-api.vue). Consider using ref() for consistency across documentation examples.

♻️ Suggested refactor for consistency
-const max = 5
-const placeholder = 'please enter a tag'
+const max = ref(5)
+const placeholder = ref('please enter a tag')
examples/sites/demos/pc/app/tag-input/prefix-suffix-composition-api.vue (1)

18-18: Consider using ref() instead of reactive() for the array.

In Vue 3 Composition API, ref() is generally preferred for arrays as it provides better type inference and is more idiomatic.

♻️ Suggested refactor
-const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])

Note: This refactor should be applied consistently across all composition API demos in this PR for uniform documentation examples.

examples/sites/demos/pc/app/tag-input/clearable-tag.vue (1)

1-20: Consider renaming data -> tags to avoid ambiguity in a demo.

data as the v-model target can read confusingly next to the data() option; tags (or similar) is clearer for docs/examples.

examples/sites/demos/pc/app/tag-input/collapsed-tag.vue (1)

1-21: Demo looks consistent; optional: rename data -> tags for readability.

examples/sites/demos/pc/app/tag-input/prefix-suffix.vue (1)

1-27: Looks good; optional: rename data -> tags for consistency with other demos and readability.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2df9671 and 5273930.

📒 Files selected for processing (20)
  • examples/sites/demos/pc/app/tag-input/basic-usage-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/basic-usage.spec.ts
  • examples/sites/demos/pc/app/tag-input/basic-usage.vue
  • examples/sites/demos/pc/app/tag-input/clearable-tag-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/clearable-tag.vue
  • examples/sites/demos/pc/app/tag-input/collapsed-tag-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/collapsed-tag.vue
  • examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/disabled-readonly.vue
  • examples/sites/demos/pc/app/tag-input/draggable-tag-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/draggable-tag.spec.ts
  • examples/sites/demos/pc/app/tag-input/draggable-tag.vue
  • examples/sites/demos/pc/app/tag-input/max-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/max.vue
  • examples/sites/demos/pc/app/tag-input/prefix-suffix-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/prefix-suffix.vue
  • examples/sites/demos/pc/app/tag-input/separator-tag-composition-api.vue
  • examples/sites/demos/pc/app/tag-input/separator-tag.vue
  • examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js
  • packages/theme/src/tag-input/index.less
🔇 Additional comments (7)
examples/sites/demos/pc/app/tag-input/basic-usage.vue (1)

4-10: LGTM! Clear demonstration of disabled state.

The multi-line formatting and disabled attribute addition effectively demonstrate the non-interactive state of the tag input component.

examples/sites/demos/pc/app/tag-input/draggable-tag.vue (1)

1-20: LGTM! Clean draggable demo implementation.

The Options API pattern is correctly implemented and clearly demonstrates the draggable feature.

examples/sites/demos/pc/app/tag-input/max.vue (1)

14-19: LGTM! Effective demonstration of the max limit.

The intentional mismatch between 6 initial tags and a max of 5 clearly demonstrates how the component handles exceeding the limit. The placeholder text reinforces this behavior.

examples/sites/demos/pc/app/tag-input/basic-usage-composition-api.vue (1)

4-10: LGTM! Consistent disabled state demonstration.

The disabled attribute addition aligns with the Options API version and clearly demonstrates the non-interactive state.

examples/sites/demos/pc/app/tag-input/separator-tag.vue (1)

1-28: LGTM!

The Options API implementation is clean and demonstrates the separator prop correctly. The component structure follows Vue best practices.

examples/sites/demos/pc/app/tag-input/separator-tag-composition-api.vue (1)

1-20: LGTM! Clean Composition API demo implementation.

The component correctly demonstrates the separator feature using Composition API patterns with reactive for the tag array and ref for primitive values. The implementation is clear and suitable for documentation purposes.

examples/sites/demos/pc/app/tag-input/disabled-readonly.vue (1)

8-29: LGTM! Clean Options API implementation.

The component correctly demonstrates both disabled and readonly states using the Options API pattern. Data initialization and component registration are appropriate for documentation purposes.

Comment on lines +7 to +14
<script setup>
import { TinyTagInput } from '@opentiny/vue'
import { reactive, ref } from 'vue'
const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const placeholder = ref('please enter a tag')
</script>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -path "*examples/sites/demos/pc/app/tag-input/clearable-tag-composition-api.vue"

Repository: opentiny/tiny-vue

Length of output: 134


🏁 Script executed:

cat "examples/sites/demos/pc/app/tag-input/clearable-tag-composition-api.vue"

Repository: opentiny/tiny-vue

Length of output: 534


🏁 Script executed:

find . -path "*TinyTagInput*" -o -path "*tag-input*" | grep -E "\.(ts|js|vue)$" | head -20

Repository: opentiny/tiny-vue

Length of output: 1323


🏁 Script executed:

rg "export.*TagInput" --type ts --type js -A 5 | head -50

Repository: opentiny/tiny-vue

Length of output: 1564


🌐 Web query:

Vue 3 v-model with reactive() vs ref() composition api

💡 Result:

Short summary — key points and practical guidance:

  • ref vs reactive (general)

    • ref(value): a Ref with .value; works for primitives and objects (objects become deeply reactive). Use when you may reassign the whole value or want an explicit ref. [1]
    • reactive(obj): returns a Proxy for objects/arrays; use for grouped/nested state when you won't replace the root object. Destructuring breaks reactivity unless you use toRefs(). [1][2]
  • v-model implications

    • v-model on a primitive prop → parent usually passes a ref (or primitive) and child emits update:modelValue; template unwrapping removes need for .value in templates. Prefer using ref for simple v-model bindings. [1]
    • v-model for object/form state → you can pass a reactive object, but props are shallow readonly (children must not mutate props directly). Instead, the child should emit updates (or receive toRef/toRefs from parent). Mutating a prop in a child triggers warnings. [2]
    • If you return/destructure reactive state for use across components/composables, convert properties to refs with toRef/toRefs so destructuring/passing preserves reactivity. [2]
  • Practical recommendations

    • Default to ref() for simple v-model values and when you may reassign the variable. [1][3]
    • Use reactive() for localized structured state (forms) in the component that owns it, but avoid replacing the root object and avoid mutating props in children — use emits or sync via v-model from parent. [1][2]
    • If sharing parts of a reactive object with children/composables, pass specific refs via toRef/toRefs or expose setter/getter computed wrappers to keep one-way flow and avoid prop mutation. [2]

References

  • Vue Reactivity API (ref, reactive). [1]
  • Vue reactivity utilities (toRef / toRefs) and v-model/props guidance. [2]
  • Opinion / best-practice summary recommending ref as a safe default. [3]

🏁 Script executed:

head -20 "examples/sites/demos/pc/app/tag-input/basic-usage-composition-api.vue"

Repository: opentiny/tiny-vue

Length of output: 730


Use ref() instead of reactive() for v-model bindings.

In Vue 3 Composition API, v-model="data" compiles to an assignment handler (@update:modelValue="value => { data = value }"). Since data is declared as const data = reactive([...]), reassignment is blocked. When TinyTagInput emits a new array, the binding fails silently. Use ref() instead:

<script setup>
 import { TinyTagInput } from '@opentiny/vue'
-import { reactive, ref } from 'vue'
+import { ref } from 'vue'

-const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])

 const placeholder = ref('please enter a tag')
</script>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<script setup>
import { TinyTagInput } from '@opentiny/vue'
import { reactive, ref } from 'vue'
const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const placeholder = ref('please enter a tag')
</script>
<script setup>
import { TinyTagInput } from '@opentiny/vue'
import { ref } from 'vue'
const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const placeholder = ref('please enter a tag')
</script>
🤖 Prompt for AI Agents
In @examples/sites/demos/pc/app/tag-input/clearable-tag-composition-api.vue
around lines 7 - 14, The v-model bound variable "data" is declared with
reactive([...]) preventing reassignment when TinyTagInput emits a new array;
change its declaration to use ref([...]) instead (i.e., replace const data =
reactive([...]) with const data = ref([...])) so v-model can assign the new
array correctly, and keep using "data" in the template (Vue will handle .value
for reactivity).

Comment on lines +1 to +6
<template>
<div class="tiny-tag-input-demo">
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly:</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
</div>
</template>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor docs polish: make the two labels consistent (readonly: vs readonly:) and consider wrapping each control in its own block for clearer layout.

🤖 Prompt for AI Agents
In @examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue
around lines 1 - 6, The labels in the template are inconsistent and cramped:
change the full-width Chinese colon after "readonly:" to an ASCII colon
"readonly:" so both labels match, and wrap each tiny-tag-input with its label in
its own block element (e.g., a div or p) to improve layout and spacing for the
two controls (update the span + tiny-tag-input pairs that reference
v-model="data" and v-model="data1").

Comment on lines +1 to +14
<template>
<div class="tiny-tag-input-demo">
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly:</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
</div>
</template>

<script setup>
import { reactive } from 'vue'
import { TinyTagInput } from '@opentiny/vue'
const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const data1 = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
</script>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "disabled-readonly-composition-api.vue" -type f

Repository: opentiny/tiny-vue

Length of output: 138


🏁 Script executed:

cat -n examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue

Repository: opentiny/tiny-vue

Length of output: 829


🌐 Web query:

Vue 3 Composition API v-model ref vs reactive binding

💡 Result:

Short answer

  • v-model expects a Ref-like value for two-way binding; in components the model exposed to the child is a ref (use defineModel() or modelValue + update:modelValue). [2][3]
  • Use ref() for single primitives or when you want to replace the whole value; use reactive() for grouped state/objects and access individual props (or convert props to refs with toRef/toRefs) when you need per-property v-model behavior. [1][4]

Why and how (concise)

  • Ref: ref(x) returns a Ref with .value; templates unwrap it so works and updating the ref updates the parent/child binding. Good for primitives or when you want the binding to replace the entire value. [1][2]
  • Reactive: reactive(obj) returns a proxy for an object. You cannot bind v-model directly to a nested property unless you reference that property (e.g. parent: reactive state; child: v-model="state.foo" — that binds the primitive property, not a Ref object). To pass a reactive object's property as a proper Ref prop you can use toRef(state, 'foo') / toRefs(state) so the child receives a Ref and two-way updates behave as expected. [1][4]
  • Components: defineModel() (or the modelValue/update:modelValue prop+emit pattern) gives you a Ref in the child that is synced with the parent — mutate it directly in the child to emit updates. defineModel() is a script-setup macro available in newer Vue 3 releases. [2][3]

Quick examples

  • Parent primitive (preferred): const count = ref(0); // child gets a Ref.
  • Parent object prop (per-property binding): const state = reactive({ name: '' }); OR expose toRef(state,'name') if you want to pass a Ref variable. [1][2][4]

Recommendation

  • For simple two-way inputs use ref. For complex forms/grouped state use reactive + toRef/toRefs for per-field v-models (or keep fields as refs inside a form object). This keeps intent clear and avoids losing reactivity when destructuring. [1][4]

Sources
[1] Vue Reactivity API (ref / reactive).
[2] Vue Guide — Component v-model (how v-model maps to a Ref in children).
[3] <script setup> API — defineModel() macro.
[4] LogRocket / community guides on ref vs reactive and best practices.


Blocker: placeholder is undefined and will cause a runtime error; also reactive([...]) is incompatible with v-model binding—use ref([...]) instead.

For two-way binding with v-model in Vue 3 Composition API, the component expects a Ref object. Using reactive() for arrays/primitives that need to be replaced entirely breaks the reactivity contract. Replace reactive() with ref() for both data and data1, and define the missing placeholder.

Fix
<script setup>
-import { reactive } from 'vue'
+import { ref } from 'vue'
 import { TinyTagInput } from '@opentiny/vue'

-const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
-const data1 = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const data1 = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
+const placeholder = ref('please enter a tag')
</script>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<template>
<div class="tiny-tag-input-demo">
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly:</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
</div>
</template>
<script setup>
import { reactive } from 'vue'
import { TinyTagInput } from '@opentiny/vue'
const data = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const data1 = reactive(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
</script>
<template>
<div class="tiny-tag-input-demo">
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly:</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { TinyTagInput } from '@opentiny/vue'
const data = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const data1 = ref(['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'])
const placeholder = ref('please enter a tag')
</script>
🤖 Prompt for AI Agents
In @examples/sites/demos/pc/app/tag-input/disabled-readonly-composition-api.vue
around lines 1 - 14, The template uses placeholder (undefined) and binds v-model
to reactive arrays which should be Refs; define a placeholder constant and
change data and data1 to use ref([...]) instead of reactive([...]) so
TinyTagInput's v-model receives a Ref; update imports to include ref and ensure
placeholder is declared in the script setup.

Comment on lines +3 to +4
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly:</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix punctuation inconsistency in label.

Line 3 uses an English colon ": " while Line 4 uses a Chinese full-width colon ":". For consistency, both labels should use the same punctuation style.

📝 Suggested fix
     <span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
-    <span>readonly:</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
+    <span>readonly: </span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly</span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
<span>disabled: </span><tiny-tag-input v-model="data" :placeholder="placeholder" disabled></tiny-tag-input>
<span>readonly: </span><tiny-tag-input v-model="data1" :placeholder="placeholder" readonly></tiny-tag-input>
🤖 Prompt for AI Agents
In @examples/sites/demos/pc/app/tag-input/disabled-readonly.vue around lines 3 -
4, Change the punctuation in the label for the readonly example to match the
disabled example: replace the Chinese full-width colon after the "readonly" span
with an English ASCII colon and space so both labels use ": " (affecting the
span before the tiny-tag-input bound to v-model="data1"); ensure the visible
text reads "readonly: " to match the "disabled: " label.

Comment on lines +50 to +52
.@{tag-input-prefix-cls}-inner:disabled {
background-color: var(--tv-TagInput-bg-color-disabled) !important;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for other uses of !important in tag-input styles
rg -n "!important" --type less -g "*tag-input*"

Repository: opentiny/tiny-vue

Length of output: 43


🏁 Script executed:

# Search for disabled prop usage in tag-input demos
rg -n -A3 -B3 "disabled.*=.*true" -g "*tag-input*" --type vue

Repository: opentiny/tiny-vue

Length of output: 88


🏁 Script executed:

# Check the tag-input index.less file to understand the CSS structure
cat -n packages/theme/src/tag-input/index.less | head -60

Repository: opentiny/tiny-vue

Length of output: 1853


🏁 Script executed:

# Search for the disabled class definition mentioned in the comment
rg -n "tag-input-prefix-cls.*disabled" --type less -A5 -B2

Repository: opentiny/tiny-vue

Length of output: 564


🏁 Script executed:

# Search for all !important in the entire theme directory
rg -n "!important" packages/theme/src/

Repository: opentiny/tiny-vue

Length of output: 2685


🏁 Script executed:

# Search for demo/example files and how they use tag-input
fd -type f -name "*.js" -o -name "*.ts" -o -name "*.vue" | grep -i "tag-input" | head -20

Repository: opentiny/tiny-vue

Length of output: 231


🏁 Script executed:

# Look at the vars.less file for tag-input to understand the color variables
cat packages/theme/src/tag-input/vars.less 2>/dev/null || echo "File not found"

Repository: opentiny/tiny-vue

Length of output: 1525


🏁 Script executed:

# Search for how the disabled attribute is applied in components
rg -n "disabled" packages/theme/src/tag-input/ --type less

Repository: opentiny/tiny-vue

Length of output: 882


🏁 Script executed:

# Check if there are other nested input selectors that might create specificity issues
rg -n "\-inner" packages/theme/src/tag-input/

Repository: opentiny/tiny-vue

Length of output: 225


🏁 Script executed:

# Search for component files that use tag-input
fd -name "*.ts" -o -name "*.tsx" | xargs grep -l "tag-input" 2>/dev/null | head -10

Repository: opentiny/tiny-vue

Length of output: 291


🏁 Script executed:

# Search for disabled attribute handling in tag-input components
rg -n "disabled" packages/components/tag-input/ 2>/dev/null | head -20

Repository: opentiny/tiny-vue

Length of output: 43


🏁 Script executed:

# Look for the component structure to understand how disabled state is applied
cat packages/components/tag-input/src/tag-input.tsx 2>/dev/null | head -100

Repository: opentiny/tiny-vue

Length of output: 43


🏁 Script executed:

# Check if there are CSS specificity issues by looking at any global styles that might affect tag-input-inner
rg -n "tag-input-inner" packages/theme/src/

Repository: opentiny/tiny-vue

Length of output: 43


🏁 Script executed:

# Find all TypeScript/Vue files in packages directory
find packages -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.vue" \) | grep -i "tag" | grep -i "input"

Repository: opentiny/tiny-vue

Length of output: 302


🏁 Script executed:

# Search more broadly for disabled state handling in tag-related files
rg "tag-input" packages/ --type ts --type tsx | head -15

Repository: opentiny/tiny-vue

Length of output: 88


🏁 Script executed:

# Look at the structure of packages directory
ls -la packages/

Repository: opentiny/tiny-vue

Length of output: 1167


🏁 Script executed:

# Search for where tag-input CSS might be imported or used
rg "tag-input/index.less" packages/

Repository: opentiny/tiny-vue

Length of output: 298


🏁 Script executed:

# Check if disabled is applied via HTML attribute in components
rg "\:disabled|disabled\s*=" packages/ --type ts --type tsx | grep -i "input" | head -10

Repository: opentiny/tiny-vue

Length of output: 150


🏁 Script executed:

# Read the tag-input component template
cat packages/vue/src/tag-input/src/pc.vue

Repository: opentiny/tiny-vue

Length of output: 2940


🏁 Script executed:

# Check the renderless logic for disabled handling
cat packages/renderless/src/tag-input/index.ts | head -150

Repository: opentiny/tiny-vue

Length of output: 3212


Remove the !important flag from the disabled input background-color.

The :disabled pseudo-class selector already provides sufficient specificity (0,2,1) to override the base .@{tag-input-prefix-cls}-inner selector (0,2,0). The !important declaration is unnecessary and complicates future style maintenance. Consider removing it and relying on the natural CSS cascade instead.

🤖 Prompt for AI Agents
In @packages/theme/src/tag-input/index.less around lines 50 - 52, Remove the
unnecessary !important from the disabled rule: in the
.@{tag-input-prefix-cls}-inner:disabled selector drop the "!important" on
background-color and rely on the :disabled specificity to apply
var(--tv-TagInput-bg-color-disabled); if you find this overridden elsewhere,
increase selector specificity (e.g., add the element or state) rather than
reintroducing !important.

demoId: 'disabled-readonly',
name: {
'zh-CN': '禁用与只读',
'en-US': 'basic usage'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

英文描述也需要同时提供下哈,这里的英文描述不正确

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js:
- Around line 34-45: The demo entry has inconsistent naming: demoId is 'max-tag'
while codeFiles refers to 'max.vue'; change the demoId value to 'max' so it
matches the codeFiles naming pattern and other entries (update the object with
keys demoId and codeFiles, i.e., adjust the demoId field for the entry that
currently has demoId: 'max-tag' and codeFiles: ['max.vue']).
🧹 Nitpick comments (1)
examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js (1)

70-81: Minor: English name inconsistency.

The en-US name 'separator tag' is singular, while similar entries use plural form ('collapsed tags', 'clearable tags', 'draggable tags'). Consider updating to 'separator tags' for consistency.

📝 Suggested fix
       name: {
         'zh-CN': '分隔符输入标签',
-        'en-US': 'separator tag'
+        'en-US': 'separator tags'
       },
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5273930 and d630375.

📒 Files selected for processing (1)
  • examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js
🔇 Additional comments (1)
examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js (1)

21-105: Documentation entries are well-structured.

The seven new demo entries follow a consistent pattern with proper localization for both Chinese and English. Each entry includes demoId, name, desc, and codeFiles as expected. The documentation additions align well with the new demo components mentioned in the PR summary.

Comment on lines +34 to +45
{
demoId: 'max-tag',
name: {
'zh-CN': '最大标签数',
'en-US': 'maximum tags'
},
desc: {
'zh-CN': `您可以设置添加标签的数量限制。<br>`,
'en-US': `You can set a limit on the number of tags to add.<br>`
},
codeFiles: ['max.vue']
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, verify the referenced demo files exist
echo "=== Checking for max.vue ==="
fd -t f 'max.vue' examples/sites/demos/pc/app/tag-input/

echo -e "\n=== Checking for max-tag.vue ==="
fd -t f 'max-tag.vue' examples/sites/demos/pc/app/tag-input/

# Read the tag-input.js file to see the actual content
echo -e "\n=== Reading tag-input.js (lines 20-100) ==="
sed -n '20,100p' examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js

Repository: opentiny/tiny-vue

Length of output: 2458


Update demoId to match the codeFiles naming pattern.

The demoId is 'max-tag' but the referenced file is 'max.vue'. All other demo entries have consistent naming (e.g., 'disabled-readonly''disabled-readonly.vue', 'collapsed-tag''collapsed-tag.vue'). Update the demoId to 'max' to align with the established pattern.

🤖 Prompt for AI Agents
In @examples/sites/demos/pc/app/tag-input/webdoc/tag-input.js around lines 34 -
45, The demo entry has inconsistent naming: demoId is 'max-tag' while codeFiles
refers to 'max.vue'; change the demoId value to 'max' so it matches the
codeFiles naming pattern and other entries (update the object with keys demoId
and codeFiles, i.e., adjust the demoId field for the entry that currently has
demoId: 'max-tag' and codeFiles: ['max.vue']).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants